
/*
    @author: breaktime1903
    @brief:  将8bit的RGB信号转换为可被HDMI使用的10bitTMDS编码信号
*/

module encoder_8bto10b(
    input logic clk,
    input logic resetn,
    input logic [7:0] din,
    input logic c0,
    input logic c1,
    input logic de,
    output logic [9:0] dout
);

// 特殊的指令数据
parameter CTRL_TOKEN0 = 10'b1101010100;
parameter CTRL_TOKEN1 = 10'b0010101011;
parameter CTRL_TOKEN2 = 10'b0101010100;
parameter CTRL_TOKEN3 = 10'b1010101011;

// 记录1和0是否过量发送
logic [5:0] cnt;
// 将输入数据锁存
logic [7:0] din_reg;
// 记录输入数据1和0的个数
logic [3:0] din_n1;
logic [3:0] din_n0;

// 锁存数据且更新1/0数量
always_ff @(posedge clk or negedge resetn) begin
    if (!resetn) begin
        din_reg <= 8'b0;
        din_n0 <= 8'd0;
        din_n1 <= 8'd0;
    end
    else begin
        din_reg <= din;
        din_n1 <= din[0] + din[1] + din[2] + din[3] + din[4] + din[5] + din[6] + din[7];
        din_n0 <= 'd8 - (din[0] + din[1] + din[2] + din[3] + din[4] + din[5] + din[6] + din[7]);
    end
end

// <条件1> 判断0多还是1多
wire condition1 = (din_n1 > 4'd4) || ((din_n1 == 4'd4) && ~din_reg[0]);
// 使用组合逻辑赋值代替时序逻辑
// 0多用异或，1多用同或
logic [8:0]q_m;
assign q_m[0] = din_reg[0];
assign q_m[1] = condition1 ? ~(din_reg[1] ^ q_m[0]) : (din_reg[1] ^ q_m[0]);
assign q_m[2] = condition1 ? ~(din_reg[2] ^ q_m[1]) : (din_reg[2] ^ q_m[1]);
assign q_m[3] = condition1 ? ~(din_reg[3] ^ q_m[2]) : (din_reg[3] ^ q_m[2]);
assign q_m[4] = condition1 ? ~(din_reg[4] ^ q_m[3]) : (din_reg[4] ^ q_m[3]);
assign q_m[5] = condition1 ? ~(din_reg[5] ^ q_m[4]) : (din_reg[5] ^ q_m[4]);
assign q_m[6] = condition1 ? ~(din_reg[6] ^ q_m[5]) : (din_reg[6] ^ q_m[5]);
assign q_m[7] = condition1 ? ~(din_reg[7] ^ q_m[6]) : (din_reg[7] ^ q_m[6]);
assign q_m[8] = condition1 ? 0 : 1;

// 锁存q_m，并计算q_m中1/0数量
logic [8:0] q_m_reg;
logic [3:0] q_m_n1;
logic [3:0] q_m_n0;
always_ff @(posedge clk or negedge resetn) begin
    if(!resetn) begin
        q_m_reg <= 9'b0;
        q_m_n1 <= 4'd0;
        q_m_n0 <= 4'd0;
    end
    else begin
        q_m_reg <= q_m;
        q_m_n1 <= q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7];
        q_m_n0 <= 'd8 - (q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7]);
    end
end

// <条件2> 上一组平衡或这一组平衡
wire condition2 = (cnt == 5'd0) || (q_m_n0 == q_m_n1);
// <条件3> 上一组和这一组都是1多/0多
wire condition3 = (cnt[5]) && (q_m_n1 > q_m_n0) || (~cnt[5]) && (q_m_n1 < q_m_n0);

// 记得将c0,c1全部打两拍对其流水线
logic [1:0] c0_reg;
logic [1:0] c1_reg;
always_ff @(posedge clk or negedge resetn) begin
    if (!resetn) begin
        c0_reg <= 2'b0;
        c1_reg <= 2'b0;
    end
    else begin
        c0_reg <= {c0_reg[0],c0};
        c1_reg <= {c1_reg[0],c1};
    end
end

always_ff @(posedge clk or negedge resetn) begin
    if(!resetn) begin
        dout <= 10'b0;
        cnt <= 5'd0;
    end
    else begin
        if(de) begin
            if(condition2) begin
                dout[9] <= ~q_m_reg[8];
                dout[8] <= q_m_reg[8];
                dout[7:0] <= (q_m_reg[8]) ? q_m_reg[7:0] : ~q_m_reg[7:0];
                if(q_m_reg[8]) begin
                    cnt <= cnt + (q_m_n1 - q_m_n0);
                end
                else begin
                    cnt <= cnt + (q_m_n0 - q_m_n1);
                end
            end
            else begin
                if(condition3) begin
                    dout[9] <= 1'b1;
                    dout[8] <= q_m_reg[8];
                    dout[7:0] <= ~q_m_reg[7:0];
                    cnt <= cnt + 2*q_m_reg[8] + (q_m_n0 - q_m_n1);
                end
                else begin
                    dout[9] <= 1'b0;
                    dout[8] <= q_m_reg[8];
                    dout[7:0] <= q_m_reg[7:0];
                    cnt <= cnt + 2*(~q_m_reg[8]) + (q_m_n1 - q_m_n0);
                end
            end
        end
        else begin
            cnt <= 5'd0;
            case ({c1_reg[1],c0_reg[1]})
                2'b00: dout <= CTRL_TOKEN0;
                2'b01: dout <= CTRL_TOKEN1;
                2'b10: dout <= CTRL_TOKEN2;
                2'b11: dout <= CTRL_TOKEN3;
            endcase
        end
    end
end

endmodule